//
//  BWMethod.m
//  CheTuoTuo
//
//  Created by Houge on 2021/1/20.
//

#import "BWMethod.h"
#import "AppDelegate.h"
#import "BaseTabBarController.h"
#import "BaseNavigationController.h"
#import "LoginViewController.h"
#import <sys/utsname.h> //获取手机型号

@implementation BWMethod

#pragma mark - 控制器相关

/// 获取window
+ (UIWindow *)getCurrentWindow {
    UIWindow *window = nil;
    if (@available(iOS 13.0, *)) {
        for (UIWindowScene *windowScene in [UIApplication sharedApplication].connectedScenes) {
            if (windowScene.activationState == UISceneActivationStateForegroundActive) {
                window = windowScene.windows.firstObject;
                break;
            }
        }
    } else {
        window = [[[UIApplication sharedApplication] delegate] window];
    }
    return window;
}

/// 获取window根视图
+ (UIViewController *)getRootViewController {
    UIWindow *window = [self getCurrentWindow];
    return window.rootViewController;
}

/// 获取当前控制器
+ (UIViewController *)getCurrentViewController {
    UIViewController *resultVC = nil;
    UIWindow *window = [self getCurrentWindow];
    
    UIView *frontView = [[window subviews] objectAtIndex:0];
    id nextResponder = [frontView nextResponder];
    
    if ([nextResponder isKindOfClass:[UIViewController class]]) {
        resultVC = nextResponder;
    } else {
        resultVC = window.rootViewController;
    }
    return resultVC;
}

#pragma mark - 获取当前屏幕显示的VC
+ (UIViewController *)dc_getCurrentVC
{
    UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    
    UIViewController *currentVC = [self getCurrentVCFrom:rootViewController];
    
    return currentVC;
}

+ (UIViewController *)getCurrentVCFrom:(UIViewController *)rootVC
{
    UIViewController *currentVC;
    
    if([rootVC presentedViewController]) {
        // 视图是被presented出来的
        rootVC = [rootVC presentedViewController];
    }
    if([rootVC isKindOfClass:[UITabBarController class]]) {
        // 根视图为UITabBarController
        currentVC = [self getCurrentVCFrom:[(UITabBarController *)rootVC selectedViewController]];
        
    }else if([rootVC isKindOfClass:[UINavigationController class]]){
        // 根视图为UINavigationController
        currentVC = [self getCurrentVCFrom:[(UINavigationController *)rootVC visibleViewController]];
        
    }else{
        // 根视图为非导航类
        currentVC = rootVC;
    }
    return currentVC;
}


#pragma mark - 压缩图片
///图片转data
+ (void)compressOriginalImage:(UIImage *)image toMaxDataSizeKBytes:(CGFloat)maxLength complete:(void (^)(NSData *imageData))complete {
    
    maxLength = maxLength * 1024;
    
    // Compress by quality
    CGFloat compression = 1;
    NSData *data = UIImageJPEGRepresentation(image, compression);
    if (data.length < maxLength){
        
        NSLog(@"初始图片符合尺寸，图片已经压缩成 %fKB",data.length/1024.0);
        complete(data);
        return;
    }
    
    CGFloat max = 1;
    CGFloat min = 0;
    for (int i = 0; i < 6; ++i) {
        compression = (max + min) / 2;
        data = UIImageJPEGRepresentation(image, compression);
        if (data.length < maxLength * 0.9) {
            min = compression;
        } else if (data.length > maxLength) {
            max = compression;
        } else {
            break;
        }
    }
    UIImage *resultImage = [UIImage imageWithData:data];
    if (data.length < maxLength) {
        
        NSLog(@"基本压缩后，图片已经压缩成 %fKB",data.length/1024.0);
        complete(data);
        return;
    }
    
    // Compress by size
    NSUInteger lastDataLength = 0;
    while (data.length > maxLength && data.length != lastDataLength) {
        lastDataLength = data.length;
        CGFloat ratio = (CGFloat)maxLength / data.length;
        CGSize size = CGSizeMake((NSUInteger)(resultImage.size.width * sqrtf(ratio)),
                                 (NSUInteger)(resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank
        UIGraphicsBeginImageContext(size);
        [resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
        resultImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        data = UIImageJPEGRepresentation(resultImage, compression);
    }
    
    NSLog(@"尺寸压缩后，图片已经压缩成 %fKB",data.length/1024.0);
    
    resultImage = [UIImage imageWithData:data];
    
    complete(data);
    return;
}

/// 压缩图片到指定文件大小 - 返回image
+ (void)compressOriginalImageToImage:(UIImage *)image toMaxDataSizeKBytes:(CGFloat)maxLength complete:(void (^)(UIImage *resultImage))complete {
    
    maxLength = maxLength * 1024;
    
    // Compress by quality
    CGFloat compression = 1;
    NSData *data = UIImageJPEGRepresentation(image, compression);
    if (data.length < maxLength){
        
        NSLog(@"初始图片符合尺寸，图片已经压缩成 %fKB",data.length/1024.0);
        complete(image);
        return;
    }
    
    CGFloat max = 1;
    CGFloat min = 0;
    for (int i = 0; i < 6; ++i) {
        compression = (max + min) / 2;
        data = UIImageJPEGRepresentation(image, compression);
        if (data.length < maxLength * 0.9) {
            min = compression;
        } else if (data.length > maxLength) {
            max = compression;
        } else {
            break;
        }
    }
    UIImage *resultImage = [UIImage imageWithData:data];
    
    if (data.length < maxLength) {
        
        NSLog(@"基本压缩后，图片已经压缩成 %fKB",data.length/1024.0);
        complete(resultImage);
        return;
    }
    
    // Compress by size
    NSUInteger lastDataLength = 0;
    while (data.length > maxLength && data.length != lastDataLength) {
        lastDataLength = data.length;
        CGFloat ratio = (CGFloat)maxLength / data.length;
        CGSize size = CGSizeMake((NSUInteger)(resultImage.size.width * sqrtf(ratio)),
                                 (NSUInteger)(resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank
        UIGraphicsBeginImageContext(size);
        [resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
        resultImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        data = UIImageJPEGRepresentation(resultImage, compression);
    }
    
    NSLog(@"尺寸压缩后，图片已经压缩成 %fKB",data.length/1024.0);
    
    resultImage = [UIImage imageWithData:data];
    
    complete(resultImage);
    return;
}


#pragma mark - 视频压缩
/// 压缩视频
+ (void)compressVideo:(NSURL *)videoUrl
    withVideoSettings:(NSDictionary *)videoSettings
        AudioSettings:(NSDictionary *)audioSettings
             fileType:(AVFileType)fileType
             complete:(void (^)(NSURL * _Nullable, NSError * _Nullable))complete {
    NSURL *outputUrl = [NSURL fileURLWithPath:[self buildOutputFilePath]];
    
    AVAsset *asset = [AVAsset assetWithURL:videoUrl];
    AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:asset error:nil];
    AVAssetWriter *writer = [AVAssetWriter assetWriterWithURL:outputUrl fileType:fileType error:nil];
    
    // video part
    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
    AVAssetReaderTrackOutput *videoOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:[self configVideoOutput]];
    AVAssetWriterInput *videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
    if ([reader canAddOutput:videoOutput]) {
        [reader addOutput:videoOutput];
    }
    if ([writer canAddInput:videoInput]) {
        [writer addInput:videoInput];
    }
    
    // audio part
    AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
    AVAssetReaderTrackOutput *audioOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:[self configAudioOutput]];
    AVAssetWriterInput *audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioSettings];
    if ([reader canAddOutput:audioOutput]) {
        [reader addOutput:audioOutput];
    }
    if ([writer canAddInput:audioInput]) {
        [writer addInput:audioInput];
    }
    
    // 开始读写
    [reader startReading];
    [writer startWriting];
    [writer startSessionAtSourceTime:kCMTimeZero];
    
    //创建视频写入队列
    dispatch_queue_t videoQueue = dispatch_queue_create("Video Queue", DISPATCH_QUEUE_SERIAL);
    //创建音频写入队列
    dispatch_queue_t audioQueue = dispatch_queue_create("Audio Queue", DISPATCH_QUEUE_SERIAL);
    //创建一个线程组
    dispatch_group_t group = dispatch_group_create();
    //进入线程组
    dispatch_group_enter(group);
    //队列准备好后 usingBlock
    [videoInput requestMediaDataWhenReadyOnQueue:videoQueue usingBlock:^{
        BOOL completedOrFailed = NO;
        while ([videoInput isReadyForMoreMediaData] && !completedOrFailed) {
            CMSampleBufferRef sampleBuffer = [videoOutput copyNextSampleBuffer];
            if (sampleBuffer != NULL) {
                [videoInput appendSampleBuffer:sampleBuffer];
                NSLog(@"===%@===", sampleBuffer);
                CFRelease(sampleBuffer);
            }
            else {
                completedOrFailed = YES;
                [videoInput markAsFinished];
                dispatch_group_leave(group);
            }
        }
    }];
    
    dispatch_group_enter(group);
    //队列准备好后 usingBlock
    [audioInput requestMediaDataWhenReadyOnQueue:audioQueue usingBlock:^{
        BOOL completedOrFailed = NO;
        while ([audioInput isReadyForMoreMediaData] && !completedOrFailed) {
            CMSampleBufferRef sampleBuffer = [audioOutput copyNextSampleBuffer];
            if (sampleBuffer != NULL) {
                BOOL success = [audioInput appendSampleBuffer:sampleBuffer];
                NSLog(@"===%@===", sampleBuffer);
                CFRelease(sampleBuffer);
                completedOrFailed = !success;
            }
            else {
                completedOrFailed = YES;
            }
        }
        
        if (completedOrFailed) {
            [audioInput markAsFinished];
            dispatch_group_leave(group);
        }
    }];
    
    //完成压缩
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        if ([reader status] == AVAssetReaderStatusReading) {
            [reader cancelReading];
        }
        
        switch (writer.status) {
            case AVAssetWriterStatusWriting: {
                NSLog(@"视频压缩完成");
                [writer finishWritingWithCompletionHandler:^{
                    
                    // 可以尝试异步回至主线程回调
                    if (complete) {
                        complete(outputUrl,nil);
                    }
                    
                }];
            }
                break;
                
            case AVAssetWriterStatusCancelled:
                NSLog(@"取消压缩");
                break;
                
            case AVAssetWriterStatusFailed:
                NSLog(@"===error：%@===", writer.error);
                if (complete) {
                    complete(nil,writer.error);
                }
                break;
                
            case AVAssetWriterStatusCompleted: {
                NSLog(@"视频压缩完成");
                [writer finishWritingWithCompletionHandler:^{
                    
                    // 可以尝试异步回至主线程回调
                    if (complete) {
                        complete(outputUrl,nil);
                    }
                }];
            }
                break;
                
            default:
                break;
        }
    });
}

/// 创建视频输出路径
+ (NSString *)buildOutputFilePath {
    NSFileManager *manager = [NSFileManager defaultManager];
    
    NSArray *docPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *documentsPath = [docPath objectAtIndex:0];
    NSString *videoPath = [NSString stringWithFormat:@"%@/MyVideo", documentsPath];
    
    // 判断文件夹是否存在
    BOOL directory = NO;
    if ([manager fileExistsAtPath:videoPath isDirectory:&directory]) {
        NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
        NSString *filePath = [videoPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%f.mp4", now]];
        NSLog(@"%@",filePath);
        [manager createFileAtPath:filePath contents:nil attributes:nil];
        return filePath;
    } else {
        // 文件夹不存在,创建文件夹
        NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
        NSString *filePath = [videoPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%f.mp4", now]];
        NSLog(@"%@",filePath);
        [manager createFileAtPath:filePath contents:nil attributes:nil];
        return filePath;
    };
}

/** 视频解码 */
+ (NSDictionary *)configVideoOutput {
    NSDictionary *videoOutputSetting = @{
        (__bridge NSString *)kCVPixelBufferPixelFormatTypeKey:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8],
        (__bridge NSString *)kCVPixelBufferIOSurfacePropertiesKey:[NSDictionary dictionary]
    };
    
    return videoOutputSetting;
}

/** 音频解码 */
+ (NSDictionary *)configAudioOutput {
    NSDictionary *audioOutputSetting = @{
        AVFormatIDKey: @(kAudioFormatLinearPCM)
    };
    return audioOutputSetting;
}

/// 指定音视频的压缩码率，profile，帧率等关键参数信息，这些参数可以根据要求自行更改
+ (NSDictionary *)performanceVideoSettings {
    NSDictionary *compressionProperties = @{
        AVVideoAverageBitRateKey          : @(409600), // 码率 400K
        AVVideoExpectedSourceFrameRateKey : @24, // 帧率
        AVVideoProfileLevelKey            : AVVideoProfileLevelH264HighAutoLevel
    };
    
    NSString *videoCodeec;
    if (@available(iOS 11.0, *)) {
        videoCodeec = AVVideoCodecTypeH264;
    } else {
        videoCodeec = AVVideoCodecH264;
    }
    NSDictionary *videoCompressSettings = @{
        AVVideoCodecKey                 : videoCodeec,
        AVVideoWidthKey                 : @640,
        AVVideoHeightKey                : @360,
        AVVideoCompressionPropertiesKey : compressionProperties,
        AVVideoScalingModeKey           : AVVideoScalingModeResizeAspectFill
    };
    
    return videoCompressSettings;
}

+ (NSDictionary *)performanceAudioSettings {
    AudioChannelLayout stereoChannelLayout = {
        .mChannelLayoutTag = kAudioChannelLayoutTag_Stereo,
        .mChannelBitmap = kAudioChannelBit_Left,
        .mNumberChannelDescriptions = 0
    };
    NSData *channelLayoutAsData = [NSData dataWithBytes:&stereoChannelLayout length:offsetof(AudioChannelLayout, mChannelDescriptions)];
    NSDictionary *audioCompressSettings = @{
        AVFormatIDKey         : @(kAudioFormatMPEG4AAC),
        AVEncoderBitRateKey   : @(49152), // 码率 48K
        AVSampleRateKey       : @44100, // 采样率
        AVChannelLayoutKey    : channelLayoutAsData,
        AVNumberOfChannelsKey : @(2)  // 声道
    };
    
    return audioCompressSettings;
}


#pragma mark - 时间相关
/// 字符串->时间
+ (NSDate *)stringToDate:(NSString *)dateStr dateFormat:(nullable NSString *)format {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = kStringIsEmpty(format) ? @"yyyy-MM-dd HH:mm:ss" : format;
    NSDate *date = [formatter dateFromString:dateStr];
    return date;
}

/// 时间->字符串
+ (NSString *)dateToString:(NSDate *)date dateFormat:(nullable NSString *)format {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = kStringIsEmpty(format) ? @"yyyy-MM-dd HH:mm:ss" : format;
    NSString *dateStr = [formatter stringFromDate:date];
    return dateStr;
}

/// 解析 时间戳
/// 返回NSDate
+ (NSDate *)timestampToDate:(NSInteger)timestamp {
    NSString *stampStr = [NSString stringWithFormat:@"%ld", timestamp];
    if (stampStr.length == 13) {
        timestamp = timestamp/1000; //传入的时间戳str如果是精确到毫秒的记得要/1000
    }
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp];
    return date;
}

/// 解析 时间戳
/// 返回NSString
+ (NSString *)timestampToDateString:(NSInteger)timestamp dateFormat:(nullable NSString *)format {
    NSDate *date = [self timestampToDate:timestamp];
    NSString *dateStr = [self dateToString:date dateFormat:format];
    return dateStr;
}

/// 字符串转时间戳
+ (NSTimeInterval)dateStringToTimestamp:(NSString *)dateString {
    NSDate *date = [self stringToDate:dateString dateFormat:nil];
    NSTimeInterval timestamp = [date timeIntervalSince1970];
    return timestamp;
}

/// 转换成 时:分:秒
+ (NSString *)timeFormatted:(NSInteger)totalSeconds {
    NSInteger seconds = totalSeconds % 60;
    NSInteger minutes = (totalSeconds / 60) % 60;
    NSInteger hours = totalSeconds / 3600;
    NSString *timeStr = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
    return timeStr;
}

/// 大于1小时, 转换成 00:00:00
/// 小于1小时, 转换成 00:00
+ (NSString *)timeFormattedBetter:(NSInteger)totalSeconds {
    NSInteger seconds = totalSeconds % 60;
    NSInteger minutes = (totalSeconds / 60) % 60;
    NSInteger hours = totalSeconds / 3600;
    NSString *timeStr = hours > 0 ? [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds] : [NSString stringWithFormat:@"%02ld:%02ld", (long)minutes, (long)seconds];
    return timeStr;
}

/// 转换成 00:00
+ (NSString *)timeFormattedToMinuteSecond:(NSInteger)totalSeconds {
    NSInteger seconds = totalSeconds % 60;
    NSInteger minutes = totalSeconds / 60;
    
    return [NSString stringWithFormat:@"%02ld:%02ld", (long)minutes, (long)seconds];
}

/// 转换成 分:秒
+ (NSString *)timeFormattedToChineseMinuteSecond:(NSInteger)totalSeconds {
    NSInteger seconds = totalSeconds % 60;
    NSInteger minutes = totalSeconds / 60;
    
    return [NSString stringWithFormat:@"%ld分%ld秒", (long)minutes, (long)seconds];
}

/// 转换日期为昨天今天
+ (NSString *)translateDateWithDateString:(NSString *)dateStr {
    NSDate *date = [self stringToDate:dateStr dateFormat:@"yyyy-MM-dd"];
    
    NSCalendar *calendar = [NSCalendar currentCalendar];
    if ([calendar isDateInTomorrow:date]) {
        return @"明天";
    } else if ([calendar isDateInToday:date]) {
        return @"今天";
    } else if ([calendar isDateInYesterday:date]) {
        return @"昨天";
    } else {
        return dateStr;
    }
}


#pragma mark - 路径相关
/// 获取Caches目录路径
+ (NSString *)getCachesPath {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask,YES);
    NSString *cachesDir = [paths lastObject];
    
    return cachesDir;
}

/// 获取path路径下文件夹大小
+ (NSString *)getCacheSizeWithFilePath:(NSString *)path {
    // 获取“path”文件夹下的所有文件
    NSArray *subPathArr = [[NSFileManager defaultManager] subpathsAtPath:path];
    
    NSString *filePath  = nil;
    NSInteger totalSize = 0;
    
    if (subPathArr.count) {
        for (NSString *subPath in subPathArr){
            // 1. 拼接每一个文件的全路径
            filePath = [path stringByAppendingPathComponent:subPath];
            // 2. 是否是文件夹，默认不是
            BOOL isDirectory = NO;
            // 3. 判断文件是否存在
            BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory];
            
            // 4. 以上判断目的是忽略不需要计算的文件
            if (!isExist || isDirectory || [filePath containsString:@".DS"]){
                // 过滤: 1. 文件夹不存在  2. 过滤文件夹  3. 隐藏文件
                continue;
            }
            
            // 5. 指定路径，获取这个路径的属性
            NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
            /**
             attributesOfItemAtPath: 文件夹路径
             该方法只能获取文件的属性, 无法获取文件夹属性, 所以也是需要遍历文件夹的每一个文件的原因
             */
            
            // 6. 获取每一个文件的大小
            NSInteger size = [dict[@"NSFileSize"] integerValue];
            
            // 7. 计算总大小
            totalSize += size;
        }
    } else {
        // path直接是文件 或者 path下没有子文件夹
        NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
        NSInteger size = [dict[@"NSFileSize"] integerValue];
        totalSize += size;
    }
    
    //8. 将文件夹大小转换为 M/KB/B
    NSString *totalStr = [self translateDataSize:totalSize];
    
    return totalStr;
}

/// 转换数据大小, 转换为 M/KB/B
+ (NSString *)translateDataSize:(NSInteger)totalSize {
    NSString *totalStr = nil;
    
    if (totalSize > 1024 * 1024) {
        totalStr = [NSString stringWithFormat:@"%.2fM",totalSize / 1024.00f /1024.00f];
        
    } else if (totalSize > 1024) {
        totalStr = [NSString stringWithFormat:@"%.2fKB",totalSize / 1024.00f];
        
    } else {
        totalStr = [NSString stringWithFormat:@"%.2fB",totalSize / 1.00f];
    }
    
    return totalStr;
}

/// 清除path文件夹下缓存
+ (BOOL)clearCacheWithFilePath:(NSString *)path {
    //拿到path路径的下一级目录的子文件夹
    NSArray *subPathArr = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
    
    NSString *filePath = nil;
    NSError *error = nil;
    
    for (NSString *subPath in subPathArr) {
        filePath = [path stringByAppendingPathComponent:subPath];
        
        //删除子文件夹
        [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
        if (error) {
            return NO;
        }
    }
    return YES;
}


#pragma mark - 文件大小

/// 获取单个文件的大小
+ (long long)fileSizeAtPath:(NSString *)filePath {
    NSFileManager *manager = [NSFileManager defaultManager];
    
    if ([manager fileExistsAtPath:filePath]){
        return [[manager attributesOfItemAtPath:filePath error:nil] fileSize];
    }
    
    return 0;
}

/// 获取文件夹的大小
+ (float)folderSizeAtPath:(NSString *)folderPath {
    NSFileManager *manager = [NSFileManager defaultManager];
    
    if (![manager fileExistsAtPath:folderPath]) return 0;
    NSEnumerator *childFilesEnumerator = [[manager subpathsAtPath:folderPath] objectEnumerator];
    NSString* fileName;
    long long folderSize = 0;
    while ((fileName = [childFilesEnumerator nextObject]) != nil)
    {
        NSString* fileAbsolutePath = [folderPath stringByAppendingPathComponent:fileName];
        folderSize += [self fileSizeAtPath:fileAbsolutePath];
    }
    
    return folderSize/(1024.0*1024.0);
}


#pragma mark - 类型转换

/// NSString转NSDictionary
+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
    if (jsonString == nil) {
        return nil;
    }
    
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *error;
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                         options:NSJSONReadingMutableContainers
                                                           error:&error];
    if(error) {
        NSLog(@"json解析失败：%@", error);
        return nil;
    }
    return dict;
}

/// NSString转NSArray dictionary
+ (NSArray *)dictArrayWithJsonString:(NSString *)jsonString {
    if (jsonString == nil) {
        return nil;
    }
    
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *error;
    NSArray *dictArray = [NSJSONSerialization JSONObjectWithData:jsonData
                                                         options:NSJSONReadingMutableContainers
                                                           error:&error];
    if(error) {
        NSLog(@"json解析失败：%@", error);
        return nil;
    }
    return dictArray;
}

/// NSObject转NSString
+ (NSString *)objectToJsonString:(id)object {
    NSString *jsonString = nil;
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object
                                                       options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
                                                         error:&error];
    if (! jsonData) {
        NSLog(@"Got an error: %@", error);
    } else {
        jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    
    // 去掉空格回车等无效字符
    NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
    NSRange range = {0, jsonString.length};
    [mutStr replaceOccurrencesOfString:@" "withString:@""options:NSLiteralSearch range:range];
    NSRange range2 = {0, mutStr.length};
    [mutStr replaceOccurrencesOfString:@"\n"withString:@""options:NSLiteralSearch range:range2];
    
    return mutStr;
    
}

/// Unicode转中文
+ (NSString *)transformUnicodeString:(NSString *)unicodeStr {
    NSString *tempStr1 = [unicodeStr stringByReplacingOccurrencesOfString:@"\\u" withString:@"\\U" options:0 range:NSMakeRange(0, unicodeStr.length)];
    NSString *tempStr2 = [tempStr1 stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
    NSString *tempStr3 = [[@"\"" stringByAppendingString:tempStr2] stringByAppendingString:@"\""];
    NSData *tempData = [tempStr3 dataUsingEncoding:NSUTF8StringEncoding];
    NSString *str = [NSPropertyListSerialization propertyListWithData:tempData options:NSPropertyListImmutable format:NULL error:NULL];
    return str;
}

+ (NSString *)dictionaryToJson:(NSDictionary *)dic {
    if (dic) {
        NSError *error;
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&error];
        NSString *jsonString;
        if (!jsonData) {
            NSLog(@"%@",error);
        }else{
            jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
        }
        NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
        NSRange range = {0,jsonString.length};
        //去掉字符串中的空格
        [mutStr replaceOccurrencesOfString:@" " withString:@"" options:NSLiteralSearch range:range];
        NSRange range2 = {0,mutStr.length};
        //去掉字符串中的换行符
        [mutStr replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:range2];
        mutStr = (NSMutableString *)[mutStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
        return mutStr;
    }else{
        return @"";
    }
}

/// 将HTML字符串转化为NSAttributedString富文本字符串
/// 解决 "<" 变成 "&lt;" 的问题
+ (NSString *)attributedStringWithHTMLString:(NSString *)htmlString {
    NSDictionary *options = @{
        NSDocumentTypeDocumentAttribute :NSHTMLTextDocumentType,
        NSCharacterEncodingDocumentAttribute :@(NSUTF8StringEncoding)
    };
    NSData *data = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
    NSAttributedString *attrStr = [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
    return attrStr.string;
}

#pragma mark - 手机号格式
+ (BOOL)verifyPhoneNumber:(NSString*)phone {
    phone = [phone stringByReplacingOccurrencesOfString:@" " withString:@""];
    if (phone.length != 11) {
        return NO;
    } else {
        NSString *regular = @"^(1[0-9])\\d{9}$";
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regular];
        BOOL isMatch = [pred evaluateWithObject:phone];
        
        if (isMatch) {
            return YES;
        } else {
            return NO;
        }
    }
}

+ (BOOL)validateEmail:(NSString *)email {
    NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
    return [emailTest evaluateWithObject:email];
}


#pragma mark - 进制转换

/// 字符串转十六进制
+ (NSString *)hexStringFromString:(NSString *)string {
    NSData *myD = [string dataUsingEncoding:NSUTF8StringEncoding];
    Byte *bytes = (Byte *)[myD bytes];
    //下面是Byte 转换为16进制。
    NSMutableString* resultStr = [[NSMutableString alloc]init];
    for (int i = 0; i < [myD length]; i++) {
        NSString *newHexStr = [NSString stringWithFormat:@"%x", bytes[i]&0xff];///16进制数
        if([newHexStr length] == 1) {
            newHexStr = [NSString stringWithFormat:@"0%@", newHexStr];
        }
        [resultStr appendString:newHexStr];
    }
    return resultStr;
}

/// 十六进制转换为普通字符串
+ (NSString *)stringFromHexString:(NSString *)hexString {
    char *myBuffer = (char *)malloc((int)[hexString length] / 2 + 1);
    bzero(myBuffer, [hexString length] / 2 + 1);
    for (int i = 0; i < [hexString length] - 1; i += 2) {
        unsigned int anInt;
        NSString * hexCharStr = [hexString substringWithRange:NSMakeRange(i, 2)];
        NSScanner * scanner = [[NSScanner alloc] initWithString:hexCharStr];
        [scanner scanHexInt:&anInt];
        myBuffer[i / 2] = (char)anInt;
    }
    NSString *unicodeString = [NSString stringWithCString:myBuffer encoding:4];
    return unicodeString;
}

#pragma mark - 手机型号

/// 获取手机型号
+ (NSString *)getPhoneType {
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *platform = [self getPlatform];
    NSString *phoneType = [self translatePhoneType:platform];
    NSLog(@"当前手机型号: %@", phoneType);
    return phoneType;
}

+ (NSString *)getPlatform {
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];
    NSLog(@"当前手机平台: %@", platform);
    return platform;
}

+ (NSString *)translatePhoneType:(NSString *)platform {
    if ([platform isEqualToString:@"iPhone1,1"]) return @"iPhone 2G";
    if ([platform isEqualToString:@"iPhone1,2"]) return @"iPhone 3G";
    if ([platform isEqualToString:@"iPhone2,1"]) return @"iPhone 3GS";
    if ([platform isEqualToString:@"iPhone3,1"]) return @"iPhone 4";
    if ([platform isEqualToString:@"iPhone3,2"]) return @"iPhone 4";
    if ([platform isEqualToString:@"iPhone3,3"]) return @"iPhone 4";
    if ([platform isEqualToString:@"iPhone4,1"]) return @"iPhone 4S";
    if ([platform isEqualToString:@"iPhone5,1"]) return @"iPhone 5";
    if ([platform isEqualToString:@"iPhone5,2"]) return @"iPhone 5";
    if ([platform isEqualToString:@"iPhone5,3"]) return @"iPhone 5c";
    if ([platform isEqualToString:@"iPhone5,4"]) return @"iPhone 5c";
    if ([platform isEqualToString:@"iPhone6,1"]) return @"iPhone 5s";
    if ([platform isEqualToString:@"iPhone6,2"]) return @"iPhone 5s";
    if ([platform isEqualToString:@"iPhone7,1"]) return @"iPhone 6 Plus";
    if ([platform isEqualToString:@"iPhone7,2"]) return @"iPhone 6";
    if ([platform isEqualToString:@"iPhone8,1"]) return @"iPhone 6s";
    if ([platform isEqualToString:@"iPhone8,2"]) return @"iPhone 6s Plus";
    if ([platform isEqualToString:@"iPhone8,4"]) return @"iPhone SE";
    if ([platform isEqualToString:@"iPhone9,1"]) return @"iPhone 7";
    if ([platform isEqualToString:@"iPhone9,2"]) return @"iPhone 7 Plus";
    if([platform isEqualToString:@"iPhone10,1"]) return @"iPhone 8";
    if([platform isEqualToString:@"iPhone10,4"]) return @"iPhone 8";
    if([platform isEqualToString:@"iPhone10,2"]) return @"iPhone 8 Plus";
    if([platform isEqualToString:@"iPhone10,5"]) return @"iPhone 8 Plus";
    if([platform isEqualToString:@"iPhone10,3"]) return @"iPhone X";
    if([platform isEqualToString:@"iPhone10,6"]) return @"iPhone X";
    if ([platform isEqualToString:@"iPhone11,8"]) return @"iPhone XR";
    if ([platform isEqualToString:@"iPhone11,2"]) return @"iPhone XS";
    if ([platform isEqualToString:@"iPhone11,6"]) return @"iPhone XS Max";
    if ([platform isEqualToString:@"iPhone11,4"]) return @"iPhone XS Max";
    if ([platform isEqualToString:@"iPhone12,1"]) return @"iPhone 11";
    if ([platform isEqualToString:@"iPhone12,3"]) return @"iPhone 11 Pro";
    if ([platform isEqualToString:@"iPhone12,5"]) return @"iPhone 11 Pro Max";
    if ([platform isEqualToString:@"iPhone12,8"]) return @"iPhone SE(2nd generation)";
    if ([platform isEqualToString:@"iPhone13,1"]) return @"iPhone 12 mini";
    if ([platform isEqualToString:@"iPhone13,2"]) return @"iPhone 12";
    if ([platform isEqualToString:@"iPhone13,3"]) return @"iPhone 12 Pro";
    if ([platform isEqualToString:@"iPhone13,4"]) return @"iPhone 12 Pro Max";
    if ([platform isEqualToString:@"iPhone14,4"]) return @"iPhone 13 mini";
    if ([platform isEqualToString:@"iPhone14,5"]) return @"iPhone 13";
    if ([platform isEqualToString:@"iPhone14,2"]) return @"iPhone 13 Pro";
    if ([platform isEqualToString:@"iPhone14,3"]) return @"iPhone 13 Pro Max";
    if ([platform isEqualToString:@"iPhone14,6"]) return @"iPhone SE (3rd generation)";
    if ([platform isEqualToString:@"iPhone14,7"]) return @"iPhone 14";
    if ([platform isEqualToString:@"iPhone14,8"]) return @"iPhone 14 Plus";
    if ([platform isEqualToString:@"iPhone15,2"]) return @"iPhone 14 Pro";
    if ([platform isEqualToString:@"iPhone15,3"]) return @"iPhone 14 Pro Max";
    if ([platform isEqualToString:@"iPod1,1"]) return @"iPod Touch 1G";
    if ([platform isEqualToString:@"iPod2,1"]) return @"iPod Touch 2G";
    if ([platform isEqualToString:@"iPod3,1"]) return @"iPod Touch 3G";
    if ([platform isEqualToString:@"iPod4,1"]) return @"iPod Touch 4G";
    if ([platform isEqualToString:@"iPod5,1"]) return @"iPod Touch 5G";
    if ([platform isEqualToString:@"iPad1,1"]) return @"iPad 1G";
    if ([platform isEqualToString:@"iPad2,1"]) return @"iPad 2";
    if ([platform isEqualToString:@"iPad2,2"]) return @"iPad 2";
    if ([platform isEqualToString:@"iPad2,3"]) return @"iPad 2";
    if ([platform isEqualToString:@"iPad2,4"]) return @"iPad 2";
    if ([platform isEqualToString:@"iPad2,5"]) return @"iPad Mini 1G";
    if ([platform isEqualToString:@"iPad2,6"]) return @"iPad Mini 1G";
    if ([platform isEqualToString:@"iPad2,7"]) return @"iPad Mini 1G";
    if ([platform isEqualToString:@"iPad3,1"]) return @"iPad 3";
    if ([platform isEqualToString:@"iPad3,2"]) return @"iPad 3";
    if ([platform isEqualToString:@"iPad3,3"]) return @"iPad 3";
    if ([platform isEqualToString:@"iPad3,4"]) return @"iPad 4";
    if ([platform isEqualToString:@"iPad3,5"]) return @"iPad 4";
    if ([platform isEqualToString:@"iPad3,6"]) return @"iPad 4";
    if ([platform isEqualToString:@"iPad4,1"]) return @"iPad Air";
    if ([platform isEqualToString:@"iPad4,2"]) return @"iPad Air";
    if ([platform isEqualToString:@"iPad4,3"]) return @"iPad Air";
    if ([platform isEqualToString:@"iPad4,4"]) return @"iPad Mini 2G";
    if ([platform isEqualToString:@"iPad4,5"]) return @"iPad Mini 2G";
    if ([platform isEqualToString:@"iPad4,6"]) return @"iPad Mini 2G";
    if ([platform isEqualToString:@"i386"]) return @"iPhone Simulator";
    if ([platform isEqualToString:@"x86_64"]) return @"iPhone Simulator";
    return platform;
}

/// 只返回数字
+ (NSInteger)getPhoneTypeNumber {
    NSString *platform = [self getPlatform];
    NSInteger phoneType = [[platform substringWithRange:NSMakeRange(6, 1)] integerValue];
    NSLog(@"当前手机型号: %ld", phoneType);
    return phoneType;
}
@end
